package com.simp.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.simp.costant.Constant;
import com.simp.dto.SysUserDto;
import com.simp.entity.SysUserEntity;
import com.simp.expection.GlobalException;
import com.simp.mapper.SysUserMapper;
import com.simp.page.R;
import com.simp.utils.DESUtils;
import com.simp.utils.JwtUtil;
import com.simp.vo.SysUserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author pan.shun
 * @version 2.0
 * @since 2021/11/8 21:50
 */
@Slf4j
@Service
public class SysUserService extends ServiceImpl<SysUserMapper, SysUserEntity> {

    @Autowired
    private Cache<String, Object> caffeineCache;

    @Autowired
    private SysLogService sysLogService;

    @Value("${tomcat-file-path}")
    private String tomcatFilePath;

    @Value("${tomcat-url:null}")
    private String tomcatUrl;

    public R getUserList(SysUserDto sysUserDto) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(
                SysUserEntity::getUserName,
                SysUserEntity::getStatus,
                SysUserEntity::getId,
                SysUserEntity::getCreateTime,
                SysUserEntity::getUpdateTime,
                SysUserEntity::getThemeId,
                SysUserEntity::getUserHead
        );
        if (!StringUtils.isEmpty(sysUserDto.getUserName())) {
            queryWrapper.like(SysUserEntity::getUserName, sysUserDto.getUserName());
        }
        queryWrapper.orderByDesc(SysUserEntity::getCreateTime);
        return R.success(this.list(queryWrapper));
    }

    public R<Object> login(HttpServletRequest request, SysUserEntity sysUserEntity) {
        long startTime = System.currentTimeMillis();
        // 加密
        String encrypt = DESUtils.Encrypt(sysUserEntity.getPassword());
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getPassword, encrypt);
        queryWrapper.eq(SysUserEntity::getUserName, sysUserEntity.getUserName());
        SysUserEntity user = this.getOne(queryWrapper);
        if (user == null) {
            throw new GlobalException("用户名或密码有误");
        }
        if (Constant.USER_STATUS.NORMAL.equals(user.getStatus())) {
            Map<String, Object> userInfo = new ConcurrentHashMap<>();
            userInfo.put("userId", user.getId());
            userInfo.put("userName", user.getUserName());
            String token = JwtUtil.createToken(user);
            userInfo.put("token", token);
            caffeineCache.put(JwtUtil.getJwtClaims(token).getAudience(), true);
            long endTime = System.currentTimeMillis();

            sysLogService.saveSysLog(
                    request,
                    user.getUserName(),
                    user.getId(),
                    Constant.LOG_STATUS.SUCCESS,
                    (float) (endTime - startTime) / 1000,
                    Constant.LOG_EVENT.LOGIN
            );
            return R.success(userInfo, "登录成功");
        } else if (Constant.USER_STATUS.AUDIT.equals(user.getStatus())) {
            long endTime = System.currentTimeMillis();
            sysLogService.saveSysLog(
                    request,
                    user.getUserName(),
                    user.getId(),
                    Constant.LOG_STATUS.SUCCESS,
                    (float) (endTime - startTime) / 1000,
                    Constant.LOG_EVENT.USER_AUDIT
            );
            throw new GlobalException("当前用户处于审核中，请联系管理员");
        } else {
            long endTime = System.currentTimeMillis();
            sysLogService.saveSysLog(
                    request,
                    user.getUserName(),
                    user.getId(),
                    Constant.LOG_STATUS.SUCCESS,
                    (float) (endTime - startTime) / 1000,
                    Constant.LOG_EVENT.USER_FORBIDDEN
            );
            throw new GlobalException("当前用户已被冻结，请联系管理员");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public R registerUser(SysUserEntity sysUserEntity) {
        doCheck(sysUserEntity);
        String encrypt = DESUtils.Encrypt(sysUserEntity.getPassword());
        sysUserEntity.setPassword(encrypt);
        sysUserEntity.setStatus(checkUser());
        this.save(sysUserEntity);
        return R.success(null, "注册成功");
    }

    /**
     * 以防初始化的时候，页面进不去
     */
    private int checkUser() {
        int count = this.count();
        if (count == 0) {
            return Constant.USER_STATUS.NORMAL;
        } else {
            return Constant.USER_STATUS.AUDIT;
        }
    }

    private void doCheck(SysUserEntity sysUserEntity) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getUserName, sysUserEntity.getUserName());
        int count = this.count(queryWrapper);
        if (count != 0) {
            throw new GlobalException("当前用户名已被注册，请换个试试");
        }
    }

    public R removeUserById(String userId, HttpServletRequest request) {
        this.removeById(userId);
        String token = request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY);
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter(Constant.TOKEN_CONFIG.TOKEN_KEY);
        }
        if (!StringUtils.isEmpty(token) && !"null".equals(token)) {
            String tokenUserId = JwtUtil.getJwtClaimsDetail(token).getUserId();
            if (userId.equals(tokenUserId)) {
                clearToken(request);
                return R.loginError();
            } else {
                return R.success(null, "删除成功");
            }
        } else {
            return R.success(null, "删除成功");
        }
    }

    public R updateUser(SysUserEntity sysUserEntity) {
        if (StringUtils.isEmpty(sysUserEntity.getId())) {
            throw new GlobalException("用户ID不能为空");
        }

        SysUserEntity user = this.getById(sysUserEntity.getId());
        if (null == user) {
            throw new GlobalException("用户不存在");
        }

        if (StringUtils.isEmpty(sysUserEntity.getUserName())) {
            sysUserEntity.setUserName(null);
        } else {
            checkName(sysUserEntity);
        }
        SysUserEntity build = SysUserEntity.builder()
                .status(sysUserEntity.getStatus())
                .userName(sysUserEntity.getUserName())
                .themeId(sysUserEntity.getThemeId()).build();
        build.setId(sysUserEntity.getId());
        this.updateById(build);
        return R.success(null, "用户信息已更新");
    }

    private void checkName(SysUserEntity sysUserEntity) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getUserName, sysUserEntity.getUserName());
        queryWrapper.ne(SysUserEntity::getId, sysUserEntity.getId());
        int count = this.count(queryWrapper);
        if (count != 0) {
            throw new GlobalException("用户名重复，请换个试试");
        }
    }

    public R updateUserPassword(SysUserVo sysUserVo) {
        checkPassword(sysUserVo);
        // 加密
        String encrypt = DESUtils.Encrypt(sysUserVo.getNewPassword());
        SysUserEntity build = SysUserEntity.builder().password(encrypt).build();
        build.setId(sysUserVo.getId());
        this.updateById(build);
        return R.success(null, "密码修改成功");
    }

    private void checkPassword(SysUserVo sysUserVo) {
        if (sysUserVo.getNewPassword().equals(sysUserVo.getOldPassword())) {
            throw new GlobalException("新密码与旧密码一致，修改失败");
        }
        if (StringUtils.isEmpty(sysUserVo.getId())) {
            throw new GlobalException("用户ID为空");
        }
        SysUserEntity sysUserEntity = this.getById(sysUserVo.getId());
        // 解密
        String decrypt = DESUtils.Decrypt(sysUserEntity.getPassword());
        if (!decrypt.equals(sysUserVo.getOldPassword())) {
            throw new GlobalException("旧密码输入有误，修改失败");
        }
    }

    private void clearToken(HttpServletRequest request) {
        String token = request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY);
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter(Constant.TOKEN_CONFIG.TOKEN_KEY);
        }
        String audience = JwtUtil.getJwtClaims(token).getAudience();
        caffeineCache.invalidate(audience);
    }

    public R loginOut(HttpServletRequest request) {
        long startTime = System.currentTimeMillis();
        clearToken(request);
        long endTime = System.currentTimeMillis();
        sysLogService.saveSysLog(
                request,
                null,
                null,
                Constant.LOG_STATUS.SUCCESS,
                (float) (endTime - startTime) / 1000,
                Constant.LOG_EVENT.LOGIN_OUT
        );

        return R.success("用户已退出");
    }

    public R uploadUserHead(MultipartFile file, String userId) {
        File dirFile = new File(tomcatFilePath + "image/");
        if (!dirFile.exists()) {
            dirFile.mkdir();
        }
        String filePath = "image/" + UUID.randomUUID() + getFileExtension(file.getOriginalFilename());
        File imageFile = new File(tomcatFilePath + filePath);
        try {
            file.transferTo(imageFile);
        } catch (IOException e) {
            throw new GlobalException("文件上传失败");
        }
        if (!StringUtils.isEmpty(tomcatUrl) && !"null".equals(tomcatUrl)) {
            SysUserEntity userEntity = this.getById(userId);
            userEntity.setUserHead(tomcatUrl + filePath);
            this.updateById(userEntity);
            return R.success(tomcatUrl + filePath);
        } else {
            log.error("请在配置文件中配置tomcat访问地址【tomcat-url】");
            throw new GlobalException("上传失败");
        }
    }

    private String getFileExtension(String fileName) {
        if (fileName.contains(".")) {
            return fileName.substring(fileName.lastIndexOf("."));
        } else {
            throw new GlobalException("文件格式有误，上传失败");
        }
    }

    public R getUserHeadByUserName(String userName) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysUserEntity::getUserHead);
        queryWrapper.eq(SysUserEntity::getUserName, userName);
        SysUserEntity entity = this.getOne(queryWrapper);
        if (entity != null) {
            return R.success(entity.getUserHead());
        } else {
            return R.success();
        }
    }

}
